﻿using Common.Extension;

namespace DesignModeConsole.行为型.迭代器模式;

//实现迭代器的快照模式  删除或者添加元素后不影响当前迭代的效果

/// <summary>
/// 迭代器接口定义
/// </summary>
/// <typeparam name="E"></typeparam>
public interface ITerator3<E>
{
    /// <summary>
    /// 是否存在下一个元素
    /// </summary>
    /// <returns></returns>
    bool HasNext();

    /// <summary>
    /// 迭代器索引往下移动一位
    /// </summary>
    E Next();
}

public interface IList3<E>
{
    ITerator3<E> Iterator();

    void Add(E item);

    void Remove(E item);
}

public class ArrayList3<E> : IList3<E>
{
    /// <summary>
    /// 默认容量
    /// </summary>
    private const int _default_capacity = 10;

    /// <summary>
    /// 不包含标记删除的元素
    /// </summary>
    public int _actualSize;

    /// <summary>
    /// 包含标记删除元素
    /// </summary>
    public int _totalSize;

    /// <summary>
    /// 元素的值
    /// </summary>
    private readonly E[] _elements;

    /// <summary>
    /// 每个值添加时候的时间戳
    /// </summary>
    private readonly long[] _addTimestamps;

    /// <summary>
    /// 移除时候的时间戳  默认的时候为最大的long，然后再删除的时候将它更新为当前时间标识已经删除
    /// </summary>
    private readonly long[] _removeTimestamps;

    public ArrayList3()
    {
        _elements = new E[_default_capacity];
        _addTimestamps = new long[_default_capacity];
        _removeTimestamps = new long[_default_capacity];
        _totalSize = 0;
        _actualSize = 0;
    }

    public void Add(E item)
    {
        _elements[_totalSize] = item;
        _addTimestamps[_totalSize] = DateTime.Now.GetTimestamp();
        _removeTimestamps[_totalSize] = long.MaxValue;
        _totalSize++;
        _actualSize++;
    }

    /// <summary>
    /// 获取快照的值
    /// </summary>
    /// <returns></returns>
    public ITerator3<E> Iterator()
    {
        return new SnapshotArrayIterator3<E>(this);
    }

    /// <summary>
    /// 移除元素 将指定元素的内容标记为已删除状态
    /// </summary>
    /// <param name="item"></param>
    public void Remove(E item)
    {
        for (var i = 0; i < _totalSize; i++)
        {
            if (_elements[i].Equals(item))
            {
                _removeTimestamps[i] = DateTime.Now.GetTimestamp();
                _actualSize--;
                break;
            }
        }
    }

    /// <summary>
    /// 获取元素
    /// </summary>
    /// <param name="i"></param>
    /// <returns></returns>
    /// <exception cref="IndexOutOfRangeException"></exception>
    public E Get(int i)
    {
        if (i >= _totalSize)
            throw new IndexOutOfRangeException("索引超出界限");

        return _elements[i];
    }

    /// <summary>
    /// 获取删除的时间戳
    /// </summary>
    /// <param name="i"></param>
    /// <returns></returns>
    /// <exception cref="IndexOutOfRangeException"></exception>
    public long GetDelTimestamp(int i)
    {
        if (i >= _totalSize)
            throw new IndexOutOfRangeException("索引超出界限");

        return _removeTimestamps[i];
    }

    public long GetAddTimestamp(int i)
    {
        if (i >= _totalSize)
            throw new IndexOutOfRangeException("索引超出界限");

        return _addTimestamps[i];
    }
}

/// <summary>
/// 快照
/// </summary>
/// <typeparam name="E"></typeparam>
public class SnapshotArrayIterator3<E> : ITerator3<E>
{
    /// <summary>
    /// 快照的时间戳
    /// </summary>
    private readonly long _snapshotTimestamp;

    /// <summary>
    /// 在整个容器的下标 非快照的下标
    /// </summary>
    private int _cursorInAll;

    /// <summary>
    /// 快照中还有几个元素未被遍历
    /// </summary>
    private int _leftCount;

    /// <summary>
    /// 当前索引是否跳过
    /// </summary>
    private bool currentSkip;

    /// <summary>
    /// 元素的值
    /// </summary>
    private readonly ArrayList3<E> _elements;

    public SnapshotArrayIterator3(ArrayList3<E> arrayList)
    {
        _snapshotTimestamp = DateTime.Now.GetTimestamp();
        _cursorInAll = 0;
        _leftCount = arrayList._actualSize;
        _elements = arrayList;
        currentSkip = true;

        // 先跳到这个迭代器快照的第一个(未删除的)元素
        JustNext();
    }

    public bool HasNext()
    {
        if (_cursorInAll >= _elements._totalSize)
            return false;
        return _leftCount >= 0;
    }

    public E Next()
    {
        var currentItem = _elements.Get(_cursorInAll);
        if (currentSkip)
            _cursorInAll++;

        JustNext();
        return currentItem;
    }

    private void JustNext()
    {
        currentSkip = false;
        while (_cursorInAll < _elements._totalSize)
        {
            var addTimestamp = _elements.GetAddTimestamp(_cursorInAll);
            var delTimestamp = _elements.GetDelTimestamp(_cursorInAll);

            // 如果元素的添加时间大于快照时间，那么就说明该元素就是后面添加的，所以不属于该迭代的快照
            // 如果快照时间大于添加时间 以及快照时间小于结束时间(未删除状态的话是long最大值)，那么就遍历了一个了
            if (_snapshotTimestamp >= addTimestamp && _snapshotTimestamp < delTimestamp)
            {
                _leftCount--;
                currentSkip = true;
                break;
            }
            _cursorInAll++;
        }
    }
}